package com.cloud.gateway.filters;

import com.cloud.common.entity.dto.WeChatLoginSessionDTO;
import com.cloud.common.utils.JwtUtil;

import lombok.extern.slf4j.Slf4j;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;

import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 全局请求过滤器
 */
@Slf4j
@Component
public class RequestGlobalFilter implements GlobalFilter, Ordered {

    // 定义前端请求的是哪个平台的关键字，"0"表示微信小程序，"1"表示管理端
    private static final String PLATFORM_KEY = "Platform";
    private static final String WECHAT = "0";
    private static final String PC = "1";

    // 定义jwt令牌存放在请求头中的哪个关键字中
    private static final String JWT_KEY = "Authorization";

    // 后续获取用户信息的关键字
    private static final String USERINFO_KEY = "user-info";

    // 放行的路径
    private static final String[] excludePath = new String[] {
            "/user/wechat/login",       // 微信用户登录
            "/user/contact/login",      // 对接人登录
            "/file/img/upload"          // 文件上传
    };

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        /* TODO 网关全局请求过滤器 */

        // 1. 获取请求体与响应体
        ServerHttpRequest request = exchange.getRequest();
       ServerHttpResponse response = exchange.getResponse();

        // 2. 判断是否需要放行请求的路径
        String path = request.getPath().value();
       if (isExcluded(path)) {
            return chain.filter(exchange);
        }

        // 3. 校验客户端访问的平台信息
        List<String> platformHeader = request.getHeaders().get(PLATFORM_KEY);
        if (platformHeader == null || platformHeader.isEmpty()) {
            log.info("未传递平台信息");
            response.setStatusCode(HttpStatus.PRECONDITION_FAILED);
            return response.setComplete();
        }
        String platform = platformHeader.get(0);
        if (!WECHAT.equals(platform) && !PC.equals(platform)) {
            log.info("平台信息传递有误");
            response.setStatusCode(HttpStatus.PRECONDITION_FAILED);
            return response.setComplete();
        }

        // 4. 校验令牌信息
       List<String> jwtHeader = request.getHeaders().get(JWT_KEY);
        if (jwtHeader == null || jwtHeader.isEmpty()){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        String jwt = jwtHeader.get(0);
        try {
            if (WECHAT.equals(platform)) {
                log.info("小程序端令牌解析...");
               WeChatLoginSessionDTO session = JwtUtil.parseJwt(jwt, WeChatLoginSessionDTO.class);
                String openid = session.getOpenid();
                ServerWebExchange swe = exchange.mutate()
                        .request(builder -> builder.header(USERINFO_KEY, openid))
                        .build();
                return chain.filter(swe);
            } else {
                log.info("PC后台令牌解析...");
                /* TODO pc后台解析令牌 */
            }
        } catch (Exception e) {
            log.info("令牌解析错误，错误信息：{}", e.getMessage());
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }

        // 执行下一个过滤器
        return chain.filter(exchange);

    }

    @Override
    public int getOrder() {
        // 设置过滤器的执行顺序，数值越小，执行越早
        return Ordered.HIGHEST_PRECEDENCE + 10;
    }

    // 判断是否是需要被放行的路径
    private Boolean isExcluded(String path) {
        for (String s : excludePath) {
            if (s.equals(path)) {
                return true;
            }
        }
        return false;
    }

}
